package com.jacky.ocr_plugin.camera;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.lifecycle.Lifecycle;

import com.jacky.util.FilePathUtils;
import com.jacky.util.OcrLogger;
import com.jacky.util.OcrRectManager;
import com.jacky.util.OcrUtil;
import com.jacky.util.PermissionUtil;

import java.util.HashMap;
import java.util.Map;

import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.view.TextureRegistry;

/**
 * 相机2的MethodCallHandler
 */
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class OcrCamera2HandlerImpl implements MethodChannel.MethodCallHandler {
    private final Activity activity;
    private final BinaryMessenger messenger;
    private final TextureRegistry textureRegistry;
    private final Lifecycle lifecycle;
    private final PermissionUtil.PermissionsRegistry permissionsRegistry;
    private final PermissionUtil.ActivityForResultRegistry activityForResultRegistry;
    private final PluginRegistry.ActivityResultListener activityResultListener = this::onActivityForResult;

    private static final int REQUEST_TAKE = 1001;
    private MethodChannel methodChannel;
    private final MethodChannel startMethodChannel;
    private CustomOcrRectView3 ocrRectView;
    private final HashMap<String,String> errorInfo = new HashMap<>();
    private final Handler mainHandler = new Handler(Looper.getMainLooper());


    public OcrCamera2HandlerImpl(Activity activity,
                                 BinaryMessenger messenger,
                                 TextureRegistry textureRegistry,
                                 Lifecycle lifecycle,
                                 PermissionUtil.PermissionsRegistry permissionsRegistry,
                                 PermissionUtil.ActivityForResultRegistry activityForResultRegistry) {
        this.activity = activity;
        this.messenger = messenger;
        this.textureRegistry = textureRegistry;
        this.lifecycle = lifecycle;
        this.permissionsRegistry = permissionsRegistry;
        this.activityForResultRegistry = activityForResultRegistry;
        //用于开启相机的初始通讯
        startMethodChannel = new MethodChannel(messenger,"com.jacky.util/ocr_view_msg");
        startMethodChannel.setMethodCallHandler(this);
    }


    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        switch (call.method) {
            case "canUse":
                Map<String, Boolean> r = new HashMap<>();
                r.put("texture", true);
                r.put("ocr", OcrRectManager.supportOcr(this.activity));
                result.success(r);
                break;
            case "initCamera":
                initCamera(call,result);
                break;
            case "startScan":
                startScan(call,result);
                break;
            case "stopScan":
                stopScan(result);
                break;
            case "toggleFlash":
                toggleFlash(result);
                break;
            case "pauseCamera":
                pauseCamera(result);
                break;
            case "stopCamera":
                stopCamera(result);
                break;
            case "resumeCamera":
                resumeCamera(result);
                break;
            case "setDimensions":
                setDimensions(call,result);
                break;
            case "takePhotoLibrary":
                takePhotoLibrary(result);
                break;
            case "takePhotoCamera":
                takePhotoCamera(call,result);
                break;
            case "switchCamera":
                switchCamera(result);
                break;
            case "updateParams":
                updateParams(call,result);
                break;
            default:
                OcrLogger.d("ocrRectView","flutter to android,notImplemented method "+call.method);
                result.notImplemented();
                break;
        }
    }

    /**
     * 创建相机
     */
    private void initCamera(MethodCall call, MethodChannel.Result result) {
        if(ocrRectView != null)ocrRectView.close();
        PermissionUtil.requestPermissions(activity,permissionsRegistry,((code, message) -> {
            if(code != null) {
                result.error(code,message,message);
                return;
            }
            instantiateCamera(call,result);
        }));
    }

    /**
     * 相机参数 初始化
     */
    private void instantiateCamera(MethodCall call, MethodChannel.Result result) {
        Boolean isFont = call.argument("cameraFont");
//        if (ocrRectView != null && ocrRectView.getCameraView() != null && lifecycle != null) {
//            lifecycle.removeObserver(ocrRectView.getCameraView());
//        }
        TextureRegistry.SurfaceTextureEntry flutterSurfaceTexture = textureRegistry.createSurfaceTexture();
        methodChannel = new MethodChannel(messenger, "com.jacky.util/ocr_view_" + flutterSurfaceTexture.id());
        methodChannel.setMethodCallHandler(this);
        CameraView cameraView = new CameraView(activity,
                flutterSurfaceTexture,
                isFont != null && isFont,
                this::errorCallback);
        ocrRectView = new CustomOcrRectView3(activity,cameraView,this::callback,this::errorCallback);
        HashMap<String, Object> data = (HashMap<String, Object>) call.arguments;
        ocrRectView.setParams(data);
//        if (lifecycle != null) {
//            lifecycle.addObserver(cameraView);
//        }
        //开启相机
        cameraView.openCamera();
        Map<String, Object> reply = new HashMap<>();
        reply.put("cameraId", flutterSurfaceTexture.id());
        result.success(reply);
    }

    private void callback(Map<String, Object> data) {
        if(methodChannel == null)return;
        String name = (String) data.get("methodName");
        mainHandler.post(()->methodChannel.invokeMethod(name == null ? "onOcrRecognize" : name, data));
    }

    private void errorCallback(String code,String message){
        if(methodChannel == null)return;
        mainHandler.post(()->{
            errorInfo.clear();
            errorInfo.put("code",code);
            errorInfo.put("message",message);
            methodChannel.invokeMethod("onOcrRectError", errorInfo);
        });
    }

    private void stopScan(MethodChannel.Result result) {
        if(checkNotCamera(result))return;
        ocrRectView.startDecoding();
    }

    private void startScan(MethodCall call, MethodChannel.Result result) {
        if(checkNotCamera(result))return;
//        HashMap<String,String> map = new HashMap<>();
        HashMap<String, Object> data = (HashMap<String, Object>) call.arguments;
        OcrLogger.d("startScan data",data.toString(),call.arguments.getClass().getSimpleName());
        ocrRectView.setParams(data);
        ocrRectView.startDecoding();
        result.success(true);
    }

    private void toggleFlash(MethodChannel.Result result) {
        if(checkNotCamera(result))return;
        result.success(ocrRectView.toggleFlashLight());
    }

    private void pauseCamera(MethodChannel.Result result) {
        if(checkNotCamera(result))return;
        ocrRectView.pause();
        result.success(true);
    }
    private void resumeCamera(MethodChannel.Result result) {
        if(checkNotCamera(result))return;
        ocrRectView.resume();
        result.success(true);
    }
    private void stopCamera(MethodChannel.Result result) {
        if(checkNotCamera(result))return;
        ocrRectView.dispose();
        result.success(true);
    }

    private void setDimensions(MethodCall call, MethodChannel.Result result) {
        if(checkNotCamera(result) || activity == null)return;
        Double aLeft = call.argument("areaLeft");
        Double aTop = call.argument("areaTop");
        Double aWidth = call.argument("areaWidth");
        Double aHeight = call.argument("areaHeight");
        Double viewWidth = call.argument("width");
        Double viewHeight = call.argument("height");
//        OcrLogger.d("ocrRectView11","flutter to android,setDimensions left "+aLeft + " top " + aTop
//                + " width "+aWidth+" height "+aHeight + " hasView " + (ocrRectView != null),
//                "viewWidth",viewWidth,"viewHeight",viewHeight);
        Context context = activity;
        int left = aLeft == null ? 0 : OcrUtil.dip2px(context,aLeft.intValue());
        int top =  aTop == null ? 0 : OcrUtil.dip2px(context,aTop.intValue());
        int width =  aWidth == null ? 0 : OcrUtil.dip2px(context,aWidth.intValue());
        int height =  aHeight == null ? 0 : OcrUtil.dip2px(context,aHeight.intValue());
        int w = viewWidth == null ? 0 : OcrUtil.dip2px(context,viewWidth.intValue());
        int h = viewHeight == null ? 0 : OcrUtil.dip2px(context,viewHeight.intValue());
        Rect rect = new Rect(left,top, left + (width > 0 ? width : w),top + (height>0?height:h));
        if(ocrRectView != null){
            //默认值 true
            ocrRectView.setRecognizeRect(rect);
            if(w > 0 && h > 0){
                HashMap<String,Object> map = new HashMap<>();
                map.put("viewWidth",OcrUtil.dip2px(context,viewWidth.intValue()));
                map.put("viewHeight",OcrUtil.dip2px(context,viewHeight.intValue()));
                ocrRectView.setParams(map);
            }
        }
        result.success(ocrRectView != null);
    }

    private void takePhotoLibrary(MethodChannel.Result result) {
        if(activity == null){
            result.error("activity","activity is null",null);
            return;
        }
        activityForResultRegistry.addListener(activityResultListener);
        Intent intent = new Intent(Intent.ACTION_PICK).setType("image/*");
        activity.startActivityForResult(intent,REQUEST_TAKE);

        result.success(true);
    }

    private void takePhotoCamera(MethodCall call,MethodChannel.Result result) {
        if(checkNotCamera(result))return;
        Boolean isWithRect = call.argument("isWithRect");
        if(isWithRect != null && isWithRect){
            ocrRectView.takePhotoCameraWithRect();
        }else{
            ocrRectView.takePicture();
        }
        result.success(true);
    }

    private void switchCamera(MethodChannel.Result result) {
        if(checkNotCamera(result))return;
        ocrRectView.switchCamera();
        result.success(true);
    }

    private void updateParams(MethodCall call, MethodChannel.Result result) {
        if(checkNotCamera(result))return;
        HashMap<String, Object> data = (HashMap<String, Object>) call.arguments;
        OcrLogger.d("update data",data.toString(),call.arguments.getClass().getSimpleName());
        ocrRectView.setParams(data);
        result.success(true);
    }

    public void stopListening() {
        if(startMethodChannel != null){
            startMethodChannel.setMethodCallHandler(null);
        }
        if(methodChannel == null)return;
        methodChannel.setMethodCallHandler(null);
    }

    private boolean checkNotCamera(MethodChannel.Result result){
        if(ocrRectView == null || !ocrRectView.hasCameraView()) {
            result.error("camera","相机未初始化",null);
            return true;
        }
        return false;
    }

    private boolean onActivityForResult(int requestCode, int resultCode, Intent data){
        if(activity == null || resultCode != Activity.RESULT_OK || requestCode != REQUEST_TAKE) return false;
        Uri uri = data == null ? null : data.getData();
        if(uri != null){
            String path = FilePathUtils.getImagePath(activity,uri);
            if(path == null || path.length() == 0) path = uri.getPath();
            HashMap<String, Object> map = new HashMap<>();
            map.put("imgPath", path);
            callback(map);
        }
        return true;
    }
}
